/**
 * RenderOptimizer - 渲染优化系统
 * 实现视锥剔除、批量渲染和其他渲染优化技术
 * @class
 */

import { Entity } from './Entity'

export interface ViewFrustum {
  /** 视锥左边界 */
  left: number
  /** 视锥右边界 */
  right: number
  /** 视锥上边界 */
  top: number
  /** 视锥下边界 */
  bottom: number
}

export interface RenderBatch {
  /** 批次中的实体列表 */
  entities: Entity[]
  /** 批次的渲染类型 */
  renderType: string
  /** 批次的纹理或精灵标识 */
  textureId?: string
}

export interface RenderOptimizerOptions {
  /** 是否启用视锥剔除 */
  enableFrustumCulling?: boolean
  /** 是否启用批量渲染 */
  enableBatching?: boolean
  /** 视锥扩展边距（像素） */
  frustumMargin?: number
  /** 最大批次大小 */
  maxBatchSize?: number
}

/**
 * 渲染优化器类
 */
export class RenderOptimizer {
  private enableFrustumCulling: boolean
  private enableBatching: boolean
  private frustumMargin: number
  private maxBatchSize: number
  private currentFrustum: ViewFrustum
  private renderBatches: Map<string, RenderBatch> = new Map()
  
  // 性能统计
  private stats = {
    totalEntities: 0,
    culledEntities: 0,
    renderedEntities: 0,
    batchCount: 0,
    lastFrameTime: 0
  }

  /**
   * 创建渲染优化器
   * @param options - 优化器配置选项
   */
  constructor(options: RenderOptimizerOptions = {}) {
    this.enableFrustumCulling = options.enableFrustumCulling ?? true
    this.enableBatching = options.enableBatching ?? true
    this.frustumMargin = options.frustumMargin ?? 50
    this.maxBatchSize = options.maxBatchSize ?? 100
    
    this.currentFrustum = {
      left: 0,
      right: 800,
      top: 0,
      bottom: 600
    }
  }

  /**
   * 更新视锥范围
   * @param frustum - 新的视锥范围
   */
  updateFrustum(frustum: ViewFrustum): void {
    this.currentFrustum = {
      left: frustum.left - this.frustumMargin,
      right: frustum.right + this.frustumMargin,
      top: frustum.top - this.frustumMargin,
      bottom: frustum.bottom + this.frustumMargin
    }
  }

  /**
   * 根据相机位置更新视锥
   * @param cameraX - 相机X坐标
   * @param cameraY - 相机Y坐标
   * @param viewWidth - 视口宽度
   * @param viewHeight - 视口高度
   */
  updateFrustumFromCamera(
    cameraX: number, 
    cameraY: number, 
    viewWidth: number, 
    viewHeight: number
  ): void {
    this.updateFrustum({
      left: cameraX - viewWidth / 2,
      right: cameraX + viewWidth / 2,
      top: cameraY - viewHeight / 2,
      bottom: cameraY + viewHeight / 2
    })
  }

  /**
   * 检查实体是否在视锥内
   * @param entity - 要检查的实体
   * @returns 如果实体在视锥内返回true
   */
  isEntityInFrustum(entity: Entity): boolean {
    if (!this.enableFrustumCulling) {
      return true
    }

    const entityLeft = entity.x
    const entityRight = entity.x + entity.width
    const entityTop = entity.y
    const entityBottom = entity.y + entity.height

    return !(
      entityRight < this.currentFrustum.left ||
      entityLeft > this.currentFrustum.right ||
      entityBottom < this.currentFrustum.top ||
      entityTop > this.currentFrustum.bottom
    )
  }

  /**
   * 对实体列表进行视锥剔除
   * @param entities - 要剔除的实体列表
   * @returns 剔除后的可见实体列表
   */
  cullEntities(entities: Entity[]): Entity[] {
    this.stats.totalEntities = entities.length
    
    if (!this.enableFrustumCulling) {
      this.stats.renderedEntities = entities.length
      this.stats.culledEntities = 0
      return entities
    }

    const visibleEntities = entities.filter(entity => {
      return entity.visible && this.isEntityInFrustum(entity)
    })

    this.stats.renderedEntities = visibleEntities.length
    this.stats.culledEntities = entities.length - visibleEntities.length

    return visibleEntities
  }

  /**
   * 将实体按渲染类型分组为批次
   * @param entities - 要分组的实体列表
   * @returns 渲染批次映射
   */
  createRenderBatches(entities: Entity[]): Map<string, RenderBatch> {
    this.renderBatches.clear()

    if (!this.enableBatching) {
      // 如果不启用批处理，每个实体单独一个批次
      entities.forEach((entity, index) => {
        const batchKey = `single_${index}`
        this.renderBatches.set(batchKey, {
          entities: [entity],
          renderType: entity.type,
          textureId: entity.sprite?.textureId
        })
      })
      return this.renderBatches
    }

    // 按渲染类型和纹理分组
    const groups = new Map<string, Entity[]>()

    for (const entity of entities) {
      const groupKey = `${entity.type}_${entity.sprite?.textureId || 'default'}`
      
      if (!groups.has(groupKey)) {
        groups.set(groupKey, [])
      }
      
      const group = groups.get(groupKey)!
      if (group.length < this.maxBatchSize) {
        group.push(entity)
      } else {
        // 如果当前组已满，创建新的批次
        const batchKey = `${groupKey}_${Math.floor(group.length / this.maxBatchSize)}`
        this.renderBatches.set(batchKey, {
          entities: [...group],
          renderType: entity.type,
          textureId: entity.sprite?.textureId
        })
        group.length = 0
        group.push(entity)
      }
    }

    // 处理剩余的组
    for (const [groupKey, entities] of groups) {
      if (entities.length > 0) {
        this.renderBatches.set(groupKey, {
          entities: [...entities],
          renderType: entities[0].type,
          textureId: entities[0].sprite?.textureId
        })
      }
    }

    this.stats.batchCount = this.renderBatches.size
    return this.renderBatches
  }

  /**
   * 优化渲染实体列表
   * @param entities - 原始实体列表
   * @returns 优化后的渲染批次
   */
  optimizeRender(entities: Entity[]): Map<string, RenderBatch> {
    const startTime = performance.now()
    
    // 1. 视锥剔除
    const visibleEntities = this.cullEntities(entities)
    
    // 2. 按距离排序（可选，用于透明度混合）
    const sortedEntities = this.sortEntitiesByDepth(visibleEntities)
    
    // 3. 创建渲染批次
    const batches = this.createRenderBatches(sortedEntities)
    
    this.stats.lastFrameTime = performance.now() - startTime
    return batches
  }

  /**
   * 按深度排序实体（Z轴排序）
   * @param entities - 要排序的实体列表
   * @returns 排序后的实体列表
   */
  private sortEntitiesByDepth(entities: Entity[]): Entity[] {
    return entities.sort((a, b) => {
      // 首先按类型排序（背景 < 游戏对象 < UI）
      const typeOrder = this.getTypeRenderOrder(a.type) - this.getTypeRenderOrder(b.type)
      if (typeOrder !== 0) {
        return typeOrder
      }
      
      // 然后按Y坐标排序（上面的先渲染）
      return a.y - b.y
    })
  }

  /**
   * 获取实体类型的渲染顺序
   * @param type - 实体类型
   * @returns 渲染顺序值（越小越先渲染）
   */
  private getTypeRenderOrder(type: string): number {
    const orderMap: Record<string, number> = {
      'BACKGROUND': 0,
      'COLLECTIBLE': 1,
      'POWERUP': 2,
      'OBSTACLE': 3,
      'BOSS': 4,
      'PROJECTILE': 5,
      'PLAYER': 6,
      'UI': 7
    }
    
    return orderMap[type] ?? 5
  }

  /**
   * 批量渲染实体
   * @param ctx - 渲染上下文
   * @param batch - 要渲染的批次
   */
  renderBatch(ctx: CanvasRenderingContext2D, batch: RenderBatch): void {
    // 如果批次有相同的纹理，可以进行优化
    if (batch.textureId && batch.entities.length > 1) {
      this.renderBatchOptimized(ctx, batch)
    } else {
      // 普通渲染
      for (const entity of batch.entities) {
        entity.render(ctx)
      }
    }
  }

  /**
   * 优化的批量渲染（适用于相同纹理的实体）
   * @param ctx - 渲染上下文
   * @param batch - 要渲染的批次
   */
  private renderBatchOptimized(ctx: CanvasRenderingContext2D, batch: RenderBatch): void {
    // 保存当前状态
    ctx.save()
    
    try {
      // 对于相同纹理的实体，可以进行批量绘制优化
      // 这里可以实现更高级的批量渲染技术
      for (const entity of batch.entities) {
        entity.render(ctx)
      }
    } finally {
      // 恢复状态
      ctx.restore()
    }
  }

  /**
   * 渲染所有批次
   * @param ctx - 渲染上下文
   */
  renderAllBatches(ctx: CanvasRenderingContext2D): void {
    for (const batch of this.renderBatches.values()) {
      this.renderBatch(ctx, batch)
    }
  }

  /**
   * 获取当前视锥范围
   * @returns 当前视锥
   */
  getCurrentFrustum(): ViewFrustum {
    return { ...this.currentFrustum }
  }

  /**
   * 设置视锥边距
   * @param margin - 新的边距值
   */
  setFrustumMargin(margin: number): void {
    this.frustumMargin = Math.max(0, margin)
  }

  /**
   * 启用或禁用视锥剔除
   * @param enabled - 是否启用
   */
  setFrustumCullingEnabled(enabled: boolean): void {
    this.enableFrustumCulling = enabled
  }

  /**
   * 启用或禁用批量渲染
   * @param enabled - 是否启用
   */
  setBatchingEnabled(enabled: boolean): void {
    this.enableBatching = enabled
  }

  /**
   * 设置最大批次大小
   * @param size - 新的最大批次大小
   */
  setMaxBatchSize(size: number): void {
    this.maxBatchSize = Math.max(1, size)
  }

  /**
   * 获取渲染统计信息
   * @returns 包含各种渲染统计数据的对象
   */
  getStats(): {
    totalEntities: number
    culledEntities: number
    renderedEntities: number
    batchCount: number
    cullRate: number
    lastFrameTime: number
    frustumCullingEnabled: boolean
    batchingEnabled: boolean
  } {
    const cullRate = this.stats.totalEntities > 0 
      ? (this.stats.culledEntities / this.stats.totalEntities) * 100 
      : 0

    return {
      ...this.stats,
      cullRate: Math.round(cullRate * 100) / 100,
      frustumCullingEnabled: this.enableFrustumCulling,
      batchingEnabled: this.enableBatching
    }
  }

  /**
   * 重置统计信息
   */
  resetStats(): void {
    this.stats = {
      totalEntities: 0,
      culledEntities: 0,
      renderedEntities: 0,
      batchCount: 0,
      lastFrameTime: 0
    }
  }

  /**
   * 清理资源
   */
  cleanup(): void {
    this.renderBatches.clear()
    this.resetStats()
  }
}